package com.hzncc.flowable_diboot.flowable.servicetask.payment;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.diboot.core.holder.ThreadLocalHolder;
import com.diboot.core.util.ContextHolder;
import com.hzncc.flowable_diboot.contract.entity.ContractAudit;
import com.hzncc.flowable_diboot.contract.entity.ContractInfo;
import com.hzncc.flowable_diboot.contract.service.ContractAuditService;
import com.hzncc.flowable_diboot.contract.service.ContractInfoService;
import com.hzncc.flowable_diboot.contract.service.impl.ContractAuditServiceImpl;
import com.hzncc.flowable_diboot.contract.service.impl.ContractInfoServiceImpl;
import com.hzncc.flowable_diboot.enums.ContractAuditStatusEnum;
import com.hzncc.flowable_diboot.payment.entity.PaymentContract;
import com.hzncc.flowable_diboot.payment.entity.SapPaymentContract;
import com.hzncc.flowable_diboot.payment.service.PaymentContractService;
import com.hzncc.flowable_diboot.payment.service.SapPaymentContractService;
import com.hzncc.flowable_diboot.payment.service.impl.PaymentContractServiceImpl;
import com.hzncc.flowable_diboot.payment.service.impl.SapPaymentContractServiceImpl;
import com.hzncc.flowable_diboot.payment.vo.PaymentContractDetailVO;
import com.hzncc.flowable_diboot.payment.vo.SapPaymentContractDetailVO;
import com.hzncc.flowable_diboot.project_contracts.entity.ProjectContractAmount;
import com.hzncc.flowable_diboot.project_contracts.entity.ProjectContractAudit;
import com.hzncc.flowable_diboot.project_contracts.service.ProjectContractAmountService;
import com.hzncc.flowable_diboot.project_contracts.service.ProjectContractAuditService;
import com.hzncc.flowable_diboot.project_contracts.service.impl.ProjectContractAmountServiceImpl;
import com.hzncc.flowable_diboot.project_contracts.service.impl.ProjectContractAuditServiceImpl;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 更新合同评审合同金额
 */
@Service
public class UpdatePaymentContractInfoAmount implements JavaDelegate {

    @Override
    @Transactional
    public void execute(DelegateExecution execution) {

        ContractAuditService contractAuditService = ContextHolder.getBean(ContractAuditServiceImpl.class);
        ContractInfoService contractInfoService = ContextHolder.getBean(ContractInfoServiceImpl.class);
        ProjectContractAuditService projectContractAuditService = ContextHolder.getBean(ProjectContractAuditServiceImpl.class);
        ProjectContractAmountService projectContractAmountService = ContextHolder.getBean(ProjectContractAmountServiceImpl.class);
        PaymentContractService paymentContractService = ContextHolder.getBean(PaymentContractServiceImpl.class);
        SapPaymentContractService sapPaymentContractService = ContextHolder.getBean(SapPaymentContractServiceImpl.class);

        String instanceId = execution.getProcessInstanceId();
        LambdaQueryWrapper<PaymentContract> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PaymentContract::getInstanceId,instanceId).eq(PaymentContract::isDeleted,0);
        ThreadLocalHolder.setIgnoreInterceptor();
        PaymentContractDetailVO paymentContractDetailVO = paymentContractService.getViewObject(queryWrapper, PaymentContractDetailVO.class);
        LambdaQueryWrapper<SapPaymentContract> sapPaymentContractQuery = new LambdaQueryWrapper<>();
        sapPaymentContractQuery.eq(SapPaymentContract::getPaymentContractId,paymentContractDetailVO.getId()).eq(SapPaymentContract::isDeleted,0);
        ThreadLocalHolder.setIgnoreInterceptor();
        List<SapPaymentContract> sapPaymentContractList = sapPaymentContractService.getEntityList(sapPaymentContractQuery);
//        List<SapPaymentContractDetailVO> sapPaymentContractList = paymentContractDetailVO.getSapPaymentContractList();
        if (!CollectionUtils.isEmpty(sapPaymentContractList)){
            Map<String, BigDecimal> currentReceivedMap = sapPaymentContractList.stream()
                    .collect(Collectors.groupingBy(item ->
                                    item.getContractCode()+"#"+item.getReviewCategory(),
                            Collectors.mapping(SapPaymentContract::getCurrentCollectionAmount,Collectors.reducing(BigDecimal.ZERO,BigDecimal::add))
                    ));
            for (Map.Entry<String,BigDecimal> entry: currentReceivedMap.entrySet()){
                String contractCodeAndReviewCategory = entry.getKey();
                String[] split = contractCodeAndReviewCategory.split("#");
                String contractCode = split[0];
                String reviewCategory = split[1];
                BigDecimal currentReceived = entry.getValue();
                if ("0".equals(reviewCategory)){
                    LambdaQueryWrapper<ContractAudit> contractAuditQuery = new LambdaQueryWrapper<>();
                    contractAuditQuery.eq(ContractAudit::getContractCode,contractCode).ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.HISTORY);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ContractAudit contractAudit = contractAuditService.getSingleEntity(contractAuditQuery);
                    String contractAuditId = contractAudit.getId();
                    LambdaQueryWrapper<ContractInfo> contractInfoQuery = new LambdaQueryWrapper<>();
                    contractInfoQuery.eq(ContractInfo::getContractAuditId,contractAuditId).eq(ContractInfo::isDeleted,0);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ContractInfo contractInfo = contractInfoService.getSingleEntity(contractInfoQuery);
                    BigDecimal totalAmount = Objects.nonNull(contractInfo.getTotalAmount())?contractInfo.getTotalAmount():BigDecimal.ZERO;
                    BigDecimal receivedAmount = Objects.nonNull(contractInfo.getReceivedAmount())?contractInfo.getReceivedAmount():BigDecimal.ZERO;
                    LambdaUpdateWrapper<ContractInfo> contractInfoUpdate = new LambdaUpdateWrapper<>();
                    contractInfoUpdate.set(ContractInfo::getReceivedAmount,receivedAmount.add(currentReceived))
                            .set(ContractInfo::getOutstandingAmount,totalAmount.subtract(contractInfo.getReceivedAmount().add(currentReceived)))
                            .eq(ContractInfo::getContractAuditId,contractAuditId);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    contractInfoService.updateEntity(contractInfoUpdate);
                }else if ("1".equals(reviewCategory)){
                    LambdaQueryWrapper<ProjectContractAudit> projectContractAuditQuery = new LambdaQueryWrapper<>();
                    projectContractAuditQuery.eq(ProjectContractAudit::getContractCode,contractCode)
                            .and(w -> w.ne(ProjectContractAudit::getContractStatus,ContractAuditStatusEnum.HISTORY.getCode()).or().eq(ProjectContractAudit::getCate,2));
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ProjectContractAudit projectContractAudit = projectContractAuditService.getSingleEntity(projectContractAuditQuery);
                    String contractAuditId = projectContractAudit.getId();
                    LambdaQueryWrapper<ProjectContractAmount> projectContractAmountQuery = new LambdaQueryWrapper<>();
                    projectContractAmountQuery.eq(ProjectContractAmount::getContractId,contractAuditId).eq(ProjectContractAmount::isDeleted,0);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    ProjectContractAmount projectContractAmount = projectContractAmountService.getSingleEntity(projectContractAmountQuery);
                    BigDecimal totalAmount = Objects.nonNull(projectContractAmount.getContractSalesTotalAmount())?projectContractAmount.getContractSalesTotalAmount():BigDecimal.ZERO;
                    BigDecimal receivedAmount = Objects.nonNull(projectContractAmount.getCollectedAmount())?projectContractAmount.getCollectedAmount():BigDecimal.ZERO;
                    LambdaUpdateWrapper<ProjectContractAmount> projectContractAmountUpdate = new LambdaUpdateWrapper<>();
                    projectContractAmountUpdate.set(ProjectContractAmount::getCollectedAmount,receivedAmount.add(currentReceived))
                            .set(ProjectContractAmount::getUncollectedAmount,totalAmount.subtract(receivedAmount.add(currentReceived)))
                            .eq(ProjectContractAmount::getContractId,contractAuditId);
                    ThreadLocalHolder.setIgnoreInterceptor();
                    projectContractAmountService.updateEntity(projectContractAmountUpdate);
                }

            }
        }
    }
}
